unit mcusim;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, Menus, Grids, Core_2313;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    lbPC: TLabel;
    lbSREG: TLabel;
    lbxMnemo: TListBox;
    MainMenu1: TMainMenu;
    Memo1: TMemo;
    mnuFile: TMenuItem;
    mnuFO: TMenuItem;
    dlgFO: TOpenDialog;
    regsgrid: TStringGrid;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure logChange(Sender: TObject);
    procedure mnuFOClick(Sender: TObject);
    procedure regsgridDrawCell(Sender: TObject; aCol, aRow: Integer;
      aRect: TRect; aState: TGridDrawState);
  private
    { private declarations }
  public
    { public declarations }
    hBIN : THandle;
    procedure RegFileRefresh;
  end;

type
  FuncGetOp = function(ins : integer) : string;
  FuncTranslateOp = function(ins : integer) : integer;
  disdata = record
    MnemoIDX      : integer;
    getop         : FuncGetOp;
  end;
{
 описатель инструкции -
   mnemo - мнемоническое обозначение инструкции
   getop - функция возвращающая строку операндов для заданной инструкции
   addr  - смещение кода на ассемблере x86 от входа в ядро симулятора
           код симулирует описываемую инструкцию
}
  TInstructionDescriptor = record
    getop         : FuncGetOp;
    translateop   : FuncTranslateOp;
    addr          : integer;
    mnemo         : string;
  end;

  TInstructionSpace = Object
    count, AND_MASK, OR_MASK  :     word;
    DES                       :     byte;

    procedure  Init;
  end;

function CORE_AVR_EXECUTE(Init : boolean) : boolean;

var
  Form1                      : TForm1;
  REG_FILE_SIZE              : integer = $1F;
  CODE_ROM_SIZE              : integer = $3FF;
  CODE                       : array [0..$3FF] of word;
  CROSS_CODE                 : array [0..$3FF] of integer;
  dcregs                     : array [0..$3FF] of word;
  RFILE                      : array [0..$3FF] of byte;
  dRFILE                     : array [0..$3FF] of byte;
  mnemonics                  : array [0..23] of string = (
   'UNKNOWN','CPC','SBC','ADD','CPSE','CP','SUB','ADC','AND','EOR','OR','MOV','CPI','SBCI','SUBI','ORI',
   'ANDI','LDI','RJMP','RETI','ICALL','OUT','IN','ASR'
  );
 {
  Описатель инструкции AVR: .addr  - метка перехода на процедуру симуляции
                            .getop - процедура возвращающая мнемонику операндов
                            .mnemo - мнемоника оператора
 }
  DES_AVR                    : array [0..100] of TInstructionDescriptor;
{
  BaseTranslator таблица которая по старшему байту инструкции выдает индекс
  в таблицы DES_AVR - описателей инструкции AVR. Если считанный индекс больше
  255 значит инструкций с таким старшим байтом более чем одна и необходимо по
  младшему байту произвести чтение расширенной таблицы трансляции ExtrTranslator
}
  BaseTranslator             : array [0..$FF] of integer;  // основной транслятор
  ExtrTranslator             : array [0..$FF] of integer;  // расширеный транслятор
  LookUpTable                : array [0..$FFFF] of byte;
  LAST_DES                   : integer = 0; // последний из определенных дескрипторов инструкции
  PC                         : integer;
  FLAGS86                    : integer;
  JmpTableInit               : boolean;
  JmpCycle                   : pointer;


const
  INS_UNK                    : integer = 0;
  JMP_NODC                   : integer = $00;
  JMP_NOP                    : integer = $00; // NOP    0000 0000 0000 0000

  INS_MOVW                   : integer = 24;
  JMP_MOVW                   : integer = $01; // MOVW   0000 0001.dddd rrrr
  iMOVW                      : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$0100; DES:24);

  INS_MULS                   : integer = 25;
  JMP_MULS                   : integer = $02; // MULS   0000 0010.dddd rrrr
  iMULS                      : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$0200; DES:25);

  INS_CPC                    : integer = 1;
  JMP_CPC                    : integer = $04; // CPC    0000 01.rd dddd rrrr    =>   00000001 . 000rrrrr . 000ddddd
  iCPC                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$0400; DES:1);

  INS_SBC                    : integer = 2;
  JMP_SBC                    : integer = $08; // SBC    0000 10.rd dddd rrrr
  iSBC                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$0800; DES:2);

  INS_ADD                    : integer = 3;
  JMP_ADD                    : integer = $0C; // ADD    0000 11.rd dddd rrrr
  iADD                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$0C00; DES:3);

  JMP_LSL                    : integer = $0C; // macro LSL    0000 11.dd dddd dddd

  INS_CPSE                   : integer = 4;
  JMP_CPSE                   : integer = $10; // CPSE   0001 00.rd dddd rrrr
  iCPSE                      : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$1000; DES:4);

  INS_CP                     : integer = 5;
  JMP_CP                     : integer = $14; // CP     0001 01.rd dddd rrrr
  iCP                        : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$1400; DES:5);

  INS_SUB                    : integer = 6;
  JMP_SUB                    : integer = $18; // SUB    0001 10.rd dddd rrrr
  iSUB                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$1800; DES:6);

  INS_ADC                    : integer = 7;
  JMP_ADC                    : integer = $1C; // ADC    0001 11.rd dddd rrrr
  iADC                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$1C00; DES:7);

  JMP_ROL                    : integer = $1C; // macro  ROL    0001 11.dd dddd dddd

  INS_AND                    : integer = 8;
  JMP_AND                    : integer = $20; // AND    0010 00.rd dddd rrrr
  iAND                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$2000; DES:8);

  INS_EOR                    : integer = 9;
  JMP_EOR                    : integer = $24; // EOR    0010 01.rd dddd rrrr
  iEOR                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$2400; DES:9);

  JMP_CLR                    : integer = $24; // macro  CLR    0010 01.dd dddd dddd

  INS_OR                     : integer = 10;
  JMP_OR                     : integer = $28; // OR     0010 10.rd dddd rrrr
  iOR                        : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$2800; DES:10);

  INS_MOV                    : integer = 11;
  JMP_MOV                    : integer = $2C; // MOV    0010 11.rd dddd rrrr
  iMOV                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$2C00; DES:11);

  INS_CPI                    : integer = 12;
  JMP_CPI                    : integer = $30; // CPI    0011 .KKKK dddd KKKK
  iCPI                       : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$3000; DES:12);

  INS_SBCI                   : integer = 13;
  JMP_SBCI                   : integer = $40; // SBCI   0100 .KKKK dddd KKKK
  iSBCI                      : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$4000; DES:13);

  INS_SUBI                   : integer = 14;
  JMP_SUBI                   : integer = $50; // SUBI   0101 .KKKK dddd KKKK
  iSUBI                      : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$5000; DES:14);

  INS_ORI                    : integer = 15;
  JMP_ORI                    : integer = $60; // ORI    0110 .KKKK dddd KKKK
  iORI                       : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$6000; DES:15);

  JMP_SBR                    : integer = $60; // macro  SBR    0110 .KKKK dddd KKKK

  INS_ANDI                   : integer = 16;
  JMP_ANDI                   : integer = $70; // ANDI   0111 .KKKK dddd KKKK
  iANDI                      : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$7000; DES:16);

  INS_ADIW                   : integer = 24;
  JMP_ADIW                   : integer = $96; // ADIW   1001 0110 .KKdd KKKK
  iADIW                      : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$9600; DES:24);

  INS_SBIW                   : integer = 25;
  JMP_SBIW                   : integer = $97; // SBIW   1001 0111 .KKdd KKKK
  iSBIW                      : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$9700; DES:25);

  INS_CBI                    : integer = 26;
  JMP_CBI                    : integer = $98; // CBI    1001 1000 .AAAA Abbb
  iCBI                       : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$9800; DES:26);

  INS_SBIC                   : integer = 27;
  JMP_SBIC                   : integer = $99; // SBIC   1001 1001 AAAA Abbb
  iSBIC                      : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$9900; DES:27);

  INS_SBI                    : integer = 28;
  JMP_SBI                    : integer = $9A; // SBI    1001 1010  AAAA Abbb
  iSBI                       : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$9A00; DES:28);

  INS_MUL                    : integer = 29;
  JMP_MUL                    : integer = $9C; // MUL    1001 11.rd dddd rrrr
  iMUL                       : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$9C00; DES:29);

  INS_SBIS                   : integer = 30;
  JMP_SBIS                   : integer = $9B; // SBIS   1001 1011 AAAA Abbb
  iSBIS                      : TInstructionSpace = (count:$00FF; AND_MASK:$00FF; OR_MASK:$9B00; DES:30);

  INS_IN                     : integer = 22;
  JMP_IN                     : integer = $B0; // IN     1011 0.AAd dddd AAAA
  iIN                        : TInstructionSpace = (count:$07FF; AND_MASK:$07FF; OR_MASK:$B000; DES:22);

  INS_OUT                    : integer = 21;
  JMP_OUT                    : integer = $B8; // OUT    1011 1.AAr rrrr AAAA
  iOUT                       : TInstructionSpace = (count:$07FF; AND_MASK:$07FF; OR_MASK:$B800; DES:21);

  INS_RJMP                   : integer = 18;
  JMP_RJMP                   : integer = $C0; // RJMP   1100 .kkkk kkkk kkkk
  iRJMP                      : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$C000; DES:18);

  INS_RCALL                  : integer = 31;
  JMP_RCALL                  : integer = $D0; // RCALL  1101 .kkkk kkkk kkkk
  iRCALL                     : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$D000; DES:31);

  INS_LDI                    : integer = 17;
  JMP_LDI                    : integer = $E0; // LDI    1110 .KKKK dddd KKKK
  iLDI                       : TInstructionSpace = (count:$0FFF; AND_MASK:$0FFF; OR_MASK:$E000; DES:17);

  JMP_SER                    : integer = $EF; // macro SER    1110 1111 dddd 1111

  INS_BRBS                   : integer = 32;
  JMP_BRBS                   : integer = $F0; // BRBS   1111 00.kk kkkk ksss
  iBRBS                      : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$F000; DES:32);

  JMP_BRCS                   : integer = $F0; // macro BRCS   1111 00.kk kkkk k000
  JMP_BRLO                   : integer = $F0; // macro BRLO   1111 00.kk kkkk k000
  JMP_BREQ                   : integer = $F0; // macro BREQ   1111 00.kk kkkk k001
  JMP_BRMI                   : integer = $F0; // macro BRMI   1111 00.kk kkkk k010
  JMP_BRVS                   : integer = $F0; // macro BRVS   1111 00.kk kkkk k011
  JMP_BRLT                   : integer = $F0; // macro BRLT   1111 00.kk kkkk k100
  JMP_BRHS                   : integer = $F0; // macro BRHS   1111 00.kk kkkk k101
  JMP_BRTS                   : integer = $F0; // macro BRTS   1111 00.kk kkkk k110
  JMP_BRIE                   : integer = $F0; // macro BRIE   1111 00.kk kkkk k111

  INS_BRBC                   : integer = 33;
  JMP_BRBC                   : integer = $F4; // BRBC   1111 01.kk kkkk ksss
  iBRBC                      : TInstructionSpace = (count:$03FF; AND_MASK:$03FF; OR_MASK:$F400; DES:33);

  JMP_BRCC                   : integer = $F4; // macro BRCC   1111 01.kk kkkk k000
  JMP_BRSH                   : integer = $F4; // macro BRSH   1111 01.kk kkkk k000
  JMP_BRNE                   : integer = $F4; // macro BRNE   1111 01.kk kkkk k001
  JMP_BRPL                   : integer = $F4; // macro BRPL   1111 01.kk kkkk k010
  JMP_BRVC                   : integer = $F4; // macro BRVC   1111 01.kk kkkk k011
  JMP_BRTC                   : integer = $F4; // macro BRTC   1111 01.kk kkkk k110
  JMP_BRGE                   : integer = $F4; // macro BRGE   1111 01.kk kkkk k100
  JMP_BRHC                   : integer = $F4; // macro BRHC   1111 01.kk kkkk k101
  JMP_BRID                   : integer = $F4; // macro BRID   1111 01.kk kkkk k111

  INS_BLD                    : integer = 34;
  JMP_BLD                    : integer = $F8; // BLD   1111 100.d dddd 0bbb
  iBLD                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F7; OR_MASK:$F800; DES:34);

  INS_BST                    : integer = 35;
  JMP_BST                    : integer = $FA; // BST    1111 101.d dddd 0bbb
  iBST                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F7; OR_MASK:$FA00; DES:35);

  INS_SBRC                   : integer = 36;
  JMP_SBRC                   : integer = $FC; // SBRC   1111 110.r rrrr 0bbb
  iSBRC                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F7; OR_MASK:$FC00; DES:36);

  INS_SBRS                   : integer = 37;
  JMP_SBRS                   : integer = $FE; // SBRS   1111 111.r rrrr 0bbb
  iSBRS                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F7; OR_MASK:$FE00; DES:37);

// инструкции совпадающие по маске старшего байта с различием в младшем
  INS_LDZQ                   : integer = 38;
  JMP_LDZQ                   : integer = $8000; // LDD Z+Q 10q0 qq0d dddd 0qqq
  iLDZQ                      : TInstructionSpace = (count:$3FFF; AND_MASK:$2DF7; OR_MASK:$8000; DES:38);

  INS_LDYQ                   : integer = 39;
  JMP_LDYQ                   : integer = $8008; // LDD Y+Q 10q0 qq0d dddd 1qqq
  iLDYQ                      : TInstructionSpace = (count:$3FFF; AND_MASK:$2DF7; OR_MASK:$8008; DES:39);

  INS_STZQ                   : integer = 40;
  JMP_STD_ZQ                 : integer = $8200; // STD Z+q 10q0 qq1.r rrrr 0qqq
  iSTZQ                      : TInstructionSpace = (count:$3FFF; AND_MASK:$2DF7; OR_MASK:$8200; DES:40);

  INS_STYQ                   : integer = 41;
  JMP_STD_YQ                 : integer = $8208; // STD Y+q 10q0 qq1.r rrrr 1qqq
  iSTYQ                      : TInstructionSpace = (count:$3FFF; AND_MASK:$2DF7; OR_MASK:$8208; DES:41);

  INS_LDS                    : integer = 42;
  JMP_LDS                    : integer = $9000; // LDS     1001 000.d dddd 0000 kkkk kkkk kkkk kkkk
  iLDS                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9000; DES:42);

  INS_LDZI                   : integer = 43;
  JMP_LD_ZI                  : integer = $9001; // LD Z+   1001 000.d dddd 0001
  iLDZI                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9001; DES:43);

  INS_LDDZ                   : integer = 44;
  JMP_LD_DZ                  : integer = $9002; // LD -Z   1001 000.d dddd 0010
  iLDDZ                      : TInstructionSpace = (count:$1FFF; AND_MASK:$01F0; OR_MASK:$9002; DES:44);

  INS_LPMR                   : integer = 45;
  JMP_LPMR                   : integer = $9004; // LPM  Z  1001 000.d dddd 0100
  iLPMR                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9004; DES:45);

  INS_LPMRZI                 : integer = 46;
  JMP_LPMRZI                 : integer = $9005; // LPM  Z+ 1001 000.d dddd 0101
  iLPMRZI                    : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9005; DES:46);

  INS_ELPMRZ                 : integer = 47;
  JMP_ELPMRZ                 : integer = $9006; // ELPM Z  1001 000.d dddd 0110
  iELPMRZ                    : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9006; DES:47);

  INS_ELPMRZI                : integer = 48;
  JMP_ELPMRZI                : integer = $9007; // ELPM Z+ 1001 000.d dddd 0111
  iELPMRZI                   : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9007; DES:48);

  INS_LDYI                   : integer = 49;
  JMP_LD_YI                  : integer = $9009; // LD Y+    1001 000.d dddd 1001
  iLDYI                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9009; DES:49);

  INS_LDDY                   : integer = 50;
  JMP_LD_DY                  : integer = $900A; // LD -Y    1001 000.d dddd 1010
  iLDDY                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$900A; DES:50);

  INS_LDX                    : integer = 51;
  JMP_LD_X                   : integer = $900C; // LD X     1001 000.d dddd 1100
  iLDX                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$900C; DES:51);

  INS_LDXI                   : integer = 52;
  JMP_LD_XI                  : integer = $900D; // LD X+    1001 000.d dddd 1101
  iLDXI                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$900D; DES:52);

  INS_LDDX                   : integer = 53;
  JMP_LD_DX                  : integer = $900E; // LD -X    1001 000.d dddd 1110
  iLDDX                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$900E; DES:53);

  INS_POP                    : integer = 54;
  JMP_POP                    : integer = $900F; // POP      1001 000.d dddd 1111
  iPOP                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$900F; DES:54);

  INS_STS                    : integer = 55;
  JMP_STS                    : integer = $9200; // STS    1001 001.d dddd 0000 kkkk kkkk kkkk kkkk
  iSTS                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9200; DES:55);

  INS_SZI                    : integer = 56;
  JMP_ST_ZI                  : integer = $9201; // ST +Z  1001 001.r rrrr 0001
  iSTZI                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9201; DES:56);

  INS_STDZ                   : integer = 57;
  JMP_ST_DZ                  : integer = $9202; // ST Z-  1001 001.r rrrr 0010
  iSTDZ                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9202; DES:57);

  INS_INC                    : integer = 58;
  JMP_INC                    : integer = $9203; // INC    1001 010.d dddd 0011
  iINC                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9203; DES:58);

  INS_STYI                   : integer = 59;
  JMP_ST_YI                  : integer = $9209; // ST +Y  1001 001.r rrrr 1001
  iSTYI                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9209; DES:59);

  INS_STDY                   : integer = 60;
  JMP_ST_DY                  : integer = $920A; // ST Y-  1001 001.r rrrr 1010
  iSTDY                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$920A; DES:60);

  INS_STX                    : integer = 61;
  JMP_STD_X                  : integer = $920C; // ST X   1001 001.r rrrr 1100
  iSTX                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$920C; DES:61);

  INS_STXI                   : integer = 62;
  JMP_ST_XI                  : integer = $920D; // ST +X  1001 001.r rrrr 1101
  iSTXI                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$920D; DES:62);

  INS_STDX                   : integer = 63;
  JMP_ST_DX                  : integer = $920E; // ST X-  1001 001.r rrrr 1110
  iSTDX                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$920E; DES:63);

  INS_PUSH                   : integer = 64;
  JMP_PUSH                   : integer = $920F; // PUSH   1001 001.d dddd 1111
  iPUSH                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$920F; DES:64);

  INS_COM                    : integer = 65;
  JMP_COM                    : integer = $9400; // COM    1001 010.d dddd 0000
  iCOM                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9400; DES:65);

  INS_NEG                    : integer = 66;
  JMP_NEG                    : integer = $9401; // NEG    1001 010.d dddd 0001
  iNEG                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9401; DES:66);

  INS_SWAP                   : integer = 67;
  JMP_SWAP                   : integer = $9402; // SWAP   1001 010.d dddd 0010
  iSWAP                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9402; DES:67);

  INS_ASR                    : integer = 23;
  JMP_ASR                    : integer = $9405; // ASR    1001 010.d dddd 0101
  iASR                      : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9405; DES:23);

  INS_LSR                    : integer = 68;
  JMP_LSR                    : integer = $9406; // LSR    1001 010.d dddd 0110
  iLSR                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9406; DES:68);

  INS_ROR                    : integer = 69;
  JMP_ROR                    : integer = $9407; // ROR    1001 010.d dddd 0111
  iROR                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$9407; DES:69);

  INS_BSET                   : integer = 70;
  JMP_BSET                   : integer = $9408; // BSET   1001 0100 0.sss 1000
  iBSET                      : TInstructionSpace = (count:$007F; AND_MASK:$01F0; OR_MASK:$9408; DES:70);

  JMP_SEC                    : integer = $9408; // macro SEC 1001 0100 .0000 1000

  INS_IJMP                   : integer = 71;
  JMP_IJMP                   : integer = $9409; // IJMP   1001 0100 .0000 1001
  iIJMP                      : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9409; DES:71);

  INS_DEC                    : integer = 72;
  JMP_DEC                    : integer = $940A; // DEC    1001 010.d dddd 1010
  iDEC                       : TInstructionSpace = (count:$01FF; AND_MASK:$01F0; OR_MASK:$940A; DES:72);

  INS_JMP                    : integer = 73;
  JMP_JMP                    : integer = $940C; // JMP    1001 010k .kkkk 110k kkkk kkkk kkkk kkkk
  iJMP                       : TInstructionSpace = (count:$01FF; AND_MASK:$01E1; OR_MASK:$940C; DES:73);

  INS_CALL                   : integer = 74;
  JMP_CALL                   : integer = $940E; // CALL   1001 010k .kkkk 111k kkkk kkkk kkkk kkkk
  iCALL                      : TInstructionSpace = (count:$01FF; AND_MASK:$01E1; OR_MASK:$940E; DES:74);

  INS_BCLR                   : integer = 75;
  JMP_BCLR                   : integer = $9488; // BCLR   1001 0100 .1sss 1000
  iBCLR                      : TInstructionSpace = (count:$007F; AND_MASK:$0070; OR_MASK:$9488; DES:75);

  JMP_CLC                    : integer = $9488; // macro CLC    1001 0100 .1000 1000
  JMP_CLZ                    : integer = $9498; // macro CLZ    1001 0100 .1001 1000
  JMP_CLN                    : integer = $94A8; // macro CLN    1001 0100 .1010 1000
  JMP_CLV                    : integer = $94B8; // macro CLZ    1001 0100 .1011 1000
  JMP_CLS                    : integer = $94C8; // macro CLS    1001 0100 .1100 1000
  JMP_CLH                    : integer = $94D8; // macro CLH    1001 0100 .1101 1000
  JMP_CLT                    : integer = $94E8; // macro CLT    1001 0100 .1110 1000
  JMP_CLI                    : integer = $94F8; // macro CLI    1001 0100 .1111 1000

  JMP_SEZ                    : integer = $9418; // macro SEZ    1001 0100 .0001 1000
  JMP_SEN                    : integer = $9428; // macro SEN    1001 0100 .0010 1000
  JMP_SEV                    : integer = $9438; // macro SEV    1001 0100 .0011 1000
  JMP_SES                    : integer = $9448; // macro SES    1001 0100 .0100 1000
  JMP_SEH                    : integer = $9458; // macro SEH    1001 0100 .0101 1000
  JMP_SET                    : integer = $9468; // macro SET    1001 0100 .0110 1000
  JMP_SEI                    : integer = $9478; // macro SEI    1001 0100 .0111 1000

  INS_EIJMP                  : integer = 76;
  JMP_EIJMP                  : integer = $9419; // EIJMP  1001 0100 0001 1001
  iEIJMP                     : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9419; DES:76);

  JMP_RETI_ICALL             : integer = $95;

  INS_RET                    : integer = 77;
  JMP_RET                    : integer = $9508; // RET    1001 0101 0000 1000
  iRET                       : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9508; DES:77);

  INS_ICALL                  : integer = 20;
  JMP_ICALL                  : integer = $9509; // ICALL  1001 0101 0000 1001
  iICALL                     : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9509; DES:20);

  INS_RETI                   : integer = 19;
  JMP_RETI                   : integer = $9518; // RETI   1001 0101 0001 1000
  iRETI                      : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9518; DES:19);

  INS_EICAL                  : integer = 78;
  JMP_EICAL                  : integer = $9519; // EICAL  1001 0101 0001 1001
  iEICAL                     : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9519; DES:78);

  INS_SLEEP                  : integer = 79;
  JMP_SLEEP                  : integer = $9588; // SLEEP  1001 0101 1000 1000
  iSLEEP                     : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9588; DES:79);

  INS_BREAK                  : integer = 80;
  JMP_BREAK                  : integer = $9598; // BREAK  1001 0101 1001 1000
  iBREAK                     : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$9598; DES:80);

  INS_WDR                    : integer = 81;
  JMP_WDR                    : integer = $95A8; // WDR    1001 0101 1010 1000
  iWDR                       : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$95A8; DES:81);

  INS_LPM                    : integer = 82;
  JMP_LPM                    : integer = $95C8; // LPM    1001 0101 1100 1000
  iLPM                       : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$95C8; DES:82);

  INS_ELPM                   : integer = 83;
  JMP_ELPM                   : integer = $95D8; // ELPM   1001 0101 1101 1000
  iELPM                      : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$95D8; DES:83);

  INS_SPM                    : integer = 84;
  JMP_SPM                    : integer = $95E8; // SPM    1001 0101 1110 1000
  iSPM                       : TInstructionSpace = (count:$0001; AND_MASK:$0000; OR_MASK:$95E8; DES:84);

  INS_MULSU                  : integer = 85;
  JMP_MULSU                  : integer = $0300; // MULSU  0000 0011 .0ddd 0rrr
  iMULSU                     : TInstructionSpace = (count:$007F; AND_MASK:$0377; OR_MASK:$0300; DES:85);

  INS_FMUL                   : integer = 86;
  JMP_FMUL                   : integer = $0308; // FMUL   0000 0011 .0ddd 1rrr
  iFMUL                      : TInstructionSpace = (count:$007F; AND_MASK:$0377; OR_MASK:$0308; DES:86);

  INS_FMULS                  : integer = 87;
  JMP_FMULS                  : integer = $0380; // FMULS  0000 0011 .1ddd 0rrr
  iFMULS                     : TInstructionSpace = (count:$007F; AND_MASK:$0377; OR_MASK:$0380; DES:87);

  INS_FMULSU                 : integer = 88;
  JMP_FMULSU                 : integer = $0388; // FMULSU 0000 0011 .1ddd 1rrr
  iFMULSU                    : TInstructionSpace = (count:$007F; AND_MASK:$0377; OR_MASK:$0388; DES:88);


// CBR

// macro BRBC => BRCC   11.11 01kk kkkk k000
// macro BRBS => BRCS   11.11 00kk kkkk k000

implementation
{ TForm1 }
procedure  TInstructionSpace.Init;
var
  i, iLUT :   word;
  oldDES  :   byte;
  test :   String;
begin
 for i:=count downto 0 do begin
  iLUT := (i AND AND_MASK) OR OR_MASK;
  oldDES := LookUpTable[iLUT];
  if((oldDES > 0) AND (oldDES<>DES)) then begin
   test:=format('cell %4.4x descriptor %2d not allocated! At the cell place descriptor %2d!', [iLUT,DES,oldDES]);
   Form1.Memo1.lines.add(test);
  end;
  LookUpTable[iLUT] := DES;
  if DES > LAST_DES then LAST_DES := DES;
//  count := count - 1;
 end;
end;

function GetOp_RR(ins : integer) : string;
var
 RR      : word;
begin
  RR := dcregs[ins AND $000003FF];
  GetOp_RR := format(' R%-2.2d, R%-2.2d',[Lo(RR), Hi(RR)]);
end;

function GetOp_NULL(ins : integer) : string;
begin
  GetOp_NULL := '';
end;

function GetOp_RK(ins : integer) : string;
var
 tmp     : integer;
begin
  tmp := ins shr 4;
  GetOp_RK := format(' R%-2.2d, %x', [(tmp and $0000000F)+$10, (tmp and $000000F0) or (ins and $0000000F)]);
end;

function GetOp_RA(ins : integer) : string;
var
 tmp     : integer;
begin
// 10.11 1AAr rrrr AAAA
  tmp := (ins shr 4) and $0000007F;
  GetOp_RA := format(' P%2.2x, R%-2.2d', [(ins and $0000000F) or ((ins shr 5) and $00000030), tmp and $0000001F]);
end;

function GetOp_AR(ins : integer) : string;
var
 tmp     : integer;
begin
// 10.11 1AAr rrrr AAAA
  tmp := (ins shr 4) and $0000007F;
  GetOp_AR := format(' R%2.2d, P%-2.2x', [tmp and $0000001F, (ins and $0000000F) or ((ins shr 5) and $00000030)]);
end;

function GetOp_OFFS(ins : integer) : string;
begin
{$ASMMODE intel}
  GetOp_OFFS := format(' %x', [(ins and $00000FFF)+1]);
end;

function TransOP_OFFS(ins : integer) : integer;
begin
  TransOP_OFFS := ins SHL (32-12);
  asm SAR  dword ptr[TransOP_OFFS], 4; end;
end;

function TransOP_RK(ins : integer) : integer;
 var
  D, K : integer;
begin
// LDI    XXXX KKKK dddd KKKK   =>     KKKKKKKK 0001dddd
  K := (ins SHR 4);
  D := (K AND $0000000F) + 16;
  K := (K AND $000000F0) OR (ins AND $0000000F);
  TransOP_RK := ((K SHL 8) OR D) SHL 16;
end;

function TransOP_empty(ins : integer) : integer;
begin
  TransOP_empty := 0;
end;

function TransOP_RD(ins : integer) : integer;
 var
   R, D : integer;
begin
// OPERANDS    XXXX XXrd dddd rrrr  =>  000rrrrr 000ddddd
  R := ins AND $0000020F;
  R := ((R SHR 5) OR R) AND $0000001F;
  D := (ins AND $000001F0) SHL 4;
  TransOP_RD := (D OR R) SHL 16;
end;

function TransOP_RA(ins : integer) : integer;
 var
   A, R : integer;
begin
// OPERANDS XXXX XAAr rrrr AAAA
  R := (ins AND $000001F0) SHR 4;
  A := ((ins SHR 5) AND $00000030) OR (ins AND $0000000F) + REG_FILE_SIZE + 1;
  TransOP_RA := (A OR (R SHL 8)) SHL 16;
end;

procedure Init;
var
  i    : integer;
begin
  core_2313.MCU_ASPACE := @RFILE;

  for i:=0 to REG_FILE_SIZE do begin
    RFILE[i]  := $FF;
    dRFILE[i] := $00;
  end;

  with DES_AVR[INS_UNK]  do begin
    getop := @GetOp_NULL;
    mnemo := 'UNKNOWN';
    translateop := @TransOP_empty;
  end;
  with DES_AVR[INS_CPC]  do begin
    translateop:=@TransOP_RD;
    getop := @GetOp_RR;
    mnemo := 'CPC';
  end;
  with DES_AVR[INS_CP]   do begin
    getop := @GetOp_RR;
    mnemo := 'CP';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_CPI]  do begin
    getop := @GetOp_RK;
    mnemo := 'CPI';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_CPSE] do begin
    getop := @GetOp_RR;
    mnemo := 'CPSE';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_ADD]  do begin
    getop := @GetOp_RR;
    mnemo := 'ADD';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_ADC]  do begin
    getop := @GetOp_RR;
    mnemo := 'ADC';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_SUB]  do begin
    getop := @GetOp_RR;
    mnemo := 'SUB';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_SBC]  do begin
    getop := @GetOp_RR;
    mnemo := 'SBC';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_SUBI] do begin
    getop := @GetOp_RK;
    mnemo := 'SUBI';
    translateop := @TransOP_RK;
  end;
  with DES_AVR[INS_SBCI] do begin
    getop := @GetOp_RK;
    mnemo := 'SBCI';
  end;
  with DES_AVR[INS_MOV]  do begin
    getop := @GetOp_RR;
    mnemo := 'MOV';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_LDI]  do begin
    getop := @GetOp_RK;
    mnemo := 'LDI';
    translateop := @TransOP_RK;
  end;
  with DES_AVR[INS_AND]  do begin
    getop := @GetOp_RR;
    mnemo := 'AND';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_ANDI] do begin
    getop := @GetOp_RK;
    mnemo := 'ANDI';
    translateop := @TransOP_RK;
  end;
  with DES_AVR[INS_OR]   do begin
    getop := @GetOp_RR;
    mnemo := 'OR';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_ORI]  do begin
    getop := @GetOp_RK;
    mnemo := 'ORI';
    translateop := @TransOP_RK;
  end;
  with DES_AVR[INS_EOR]  do begin
    getop := @GetOp_RR;
    mnemo := 'EOR';
    translateop := @TransOP_RD;
  end;
  with DES_AVR[INS_RJMP] do begin
    getop := @GetOp_OFFS;
    mnemo := 'RJMP';
    translateop := @TransOP_OFFS;
  end;
  with DES_AVR[INS_RETI] do begin
    getop := @GetOp_NULL;
    mnemo := 'RETI';
    translateop := @TransOP_empty;
  end;
  with DES_AVR[INS_ICALL] do begin
    getop := @GetOp_NULL;
    mnemo := 'ICALL';
    translateop := @TransOP_empty;
  end;
  with DES_AVR[INS_OUT] do begin
    getop := @GetOp_RA;
    mnemo := 'OUT';
    translateop := @TransOP_RA;
  end;
  with DES_AVR[INS_IN] do begin
    getop := @GetOp_AR;
    mnemo := 'IN';
    translateop := @TransOP_RA;
  end;
  CORE_AVR_EXECUTE(true);
  for i:=0 to $FF do begin
    BaseTranslator[i] := INS_UNK;
    ExtrTranslator[i] := INS_UNK;
  end;

  for i:=0 to $FFFF do LookUpTable[i] := 0;

  iMOVW.Init;
  iMULS.Init;
  iCPC.Init;
  iSBC.Init;
  iADD.Init;
  iCPSE.Init;
  iCP.Init;
  iSUB.Init;
  iADC.Init;
  iAND.Init;
  iEOR.Init;
  iOR.Init;
  iMOV.Init;
  iCPI.Init;
  iSBCI.Init;
  iSUBI.Init;
  iORI.Init;
  iANDI.Init;
  iADIW.Init;
  iSBIW.Init;
  iCBI.Init;
  iSBIC.Init;
  iSBI.Init;
  iMUL.Init;
  iSBIS.Init;
  iIN.Init;
  iOUT.Init;
  iRJMP.Init;
  iRCALL.Init;
  iLDI.Init;
  iBRBS.Init;
  iBRBC.Init;
  iBLD.Init;
  iBST.Init;
  iSBRC.Init;
  iSBRS.Init;
  iLDZQ.Init;
  iLDYQ.Init;
  iSTZQ.Init;
  iSTYQ.Init;
  iLDS.Init;
  iLDZI.Init;
  iLDDZ.Init;
  iLPMR.Init;
  iLPMRZI.Init;
  iELPMRZ.Init;
  iELPMRZI.Init;
  iLDYI.Init;
  iLDDY.Init;
  iLDX.Init;
  iLDXI.Init;
  iLDDX.Init;
  iPOP.Init;
  iSTS.Init;
  iSTZI.Init;
  iSTDZ.Init;
  iINC.Init;
  iSTYI.Init;
  iSTDY.Init;
  iSTDX.Init;
  iSTXI.Init;
  iSTX.Init;
  iPUSH.Init;
  iCOM.Init;
  iNEG.Init;
  iSWAP.Init;
  iASR.Init;
  iLSR.Init;
  iROR.Init;
  iBSET.Init;
  iIJMP.Init;
  iDEC.Init;
  iJMP.Init;
  iCALL.Init;
  iBCLR.Init;
  iEIJMP.Init;
  iRET.Init;
  iICALL.Init;
  iRETI.Init;
  iEICAL.Init;
  iSLEEP.Init;
  iBREAK.Init;
  iWDR.Init;
  iLPM.Init;
  iELPM.Init;
  iSPM.Init;
  iMULSU.Init;
  iFMUL.Init;
  iFMULS.Init;
  iFMULSU.Init;
end;

function CORE_AVR_EXECUTE(Init : boolean) : boolean;
label
 AVR_START_CORE, AVR_FETCH, AVR_UNKNOWN,
 AVR_MOV, AVR_LDI,
 AVR_CPC, AVR_CP, AVR_CPI, AVR_CPSE, AVR_CPSE_Cycle_1,
 AVR_SUB, AVR_SUBI, AVR_SBC, AVR_SBCI,
 AVR_ADD, AVR_ADC,
 AVR_OR, AVR_ORI,
 AVR_AND, AVR_ANDI,
 AVR_EOR,
 AVR_RJMP,
 AVR_IN, AVR_OUT;
begin
if Init then begin
  DES_AVR[INS_UNK].addr  := @AVR_UNKNOWN - @AVR_START_CORE;
  DES_AVR[INS_MOV].addr  := @AVR_MOV     - @AVR_START_CORE;
  DES_AVR[INS_CP].addr   := @AVR_CP      - @AVR_START_CORE;
  DES_AVR[INS_CPC].addr  := @AVR_CPC     - @AVR_START_CORE;
  DES_AVR[INS_CPI].addr  := @AVR_CPI     - @AVR_START_CORE;
  DES_AVR[INS_CPSE].addr := @AVR_CPSE    - @AVR_START_CORE;
  DES_AVR[INS_ADD].addr  := @AVR_ADD     - @AVR_START_CORE;
  DES_AVR[INS_ADC].addr  := @AVR_ADC     - @AVR_START_CORE;
  DES_AVR[INS_SUB].addr  := @AVR_SUB     - @AVR_START_CORE;
  DES_AVR[INS_SBC].addr  := @AVR_SBC     - @AVR_START_CORE;
  DES_AVR[INS_SBCI].addr := @AVR_SBCI    - @AVR_START_CORE;
  DES_AVR[INS_SUBI].addr := @AVR_SUBI    - @AVR_START_CORE;
  DES_AVR[INS_LDI].addr  := @AVR_LDI     - @AVR_START_CORE;
  DES_AVR[INS_OR].addr   := @AVR_OR      - @AVR_START_CORE;
  DES_AVR[INS_ORI].addr  := @AVR_ORI     - @AVR_START_CORE;
  DES_AVR[INS_AND].addr  := @AVR_AND     - @AVR_START_CORE;
  DES_AVR[INS_ANDI].addr := @AVR_ANDI    - @AVR_START_CORE;
  DES_AVR[INS_EOR].addr  := @AVR_EOR     - @AVR_START_CORE;
  DES_AVR[INS_RJMP].addr := @AVR_RJMP    - @AVR_START_CORE;
  DES_AVR[INS_OUT].addr  := @AVR_OUT     - @AVR_START_CORE;
  DES_AVR[INS_IN].addr   := @AVR_IN      - @AVR_START_CORE;
  JmpCycle               := @AVR_FETCH;
end
else begin
{$ASMMODE intel}
asm
     mov      EDX, PC
     jmp      [JmpCycle]
AVR_FETCH:

     mov      ECX, dword ptr[CROSS_CODE + EDX*4]
     mov      EAX, offset AVR_START_CORE

     mov      EBX, ECX
     add      EDX, 1

     and      ECX, $0000FFFF
     add      EAX, ECX

     jmp      EAX
AVR_START_CORE:
@AVR_STARTMOP:
AVR_IN:
// входные параметры BL - target, BH - port address
     bswap    EBX

     movzx    EAX, BH
     and      EBX, $000000FF

     mov      ECX,  dword ptr[RFILE+EAX]
     mov      byte ptr [RFILE+EBX], CL

     jmp     @AVR_EXIT
AVR_OUT:
// входные параметры BL - source, BH - port address
     bswap    EBX

     movzx    EAX, BH
     and      EBX, $000000FF

     mov      ECX, dword ptr [RFILE+EBX]
     mov      byte ptr[RFILE+EAX], CL

     jmp     @AVR_EXIT
AVR_MOV:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     mov     byte ptr[RFILE+EBX], CL
     jmp     @AVR_EXIT
AVR_CPC:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     sahf

     sbb     byte ptr[RFILE+EBX], CL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_SBC:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     sahf

     sbb     byte ptr[RFILE+EBX], CL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_ADD:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     add     byte ptr[RFILE+EBX], CL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_CPSE:
// входные параметры BL - destantion, BH - source, EDX - счетчик команд
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     cmp     byte ptr[RFILE+EBX], CL
     jnz     @AVR_EXIT

     mov     JmpCycle, offset AVR_CPSE_Cycle_1
     add     EDX, 1

     jmp     @AVR_EXIT
AVR_CPI:
// входные параметры BL - immediate constant, BH - destantion
     bswap   EBX

     mov     EAX, dword ptr [FLAGS86]

     movzx   ECX, BH
     sahf

     cmp     byte ptr[RFILE+ECX], BL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_SBCI:
// входные параметры BL - immediate constant, BH - destantion
     bswap   EBX

     mov     EAX, dword ptr [FLAGS86]

     movzx   ECX, BH
     sahf

     sbb     byte ptr[RFILE+ECX], BL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_SUBI:
// входные параметры BL - immediate constant, BH - destantion
     bswap   EBX

     movzx   ECX, BH

     sub     byte ptr[RFILE+ECX], BL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_ORI:
// входные параметры BL - immediate constant, BH - destantion
     bswap   EBX

     movzx   ECX, BH

     or      byte ptr[RFILE+ECX], BL
     lahf

     mov     dword ptr [FLAGS86], EAX
     jmp     @AVR_EXIT
AVR_ANDI:
// входные параметры BL - immediate constant, BH - destantion
     bswap   EBX

     movzx   ECX, BH

     and     byte ptr[RFILE+ECX], BL
     lahf

     mov     dword ptr [FLAGS86], EAX
     jmp     @AVR_EXIT
AVR_LDI:
// входные параметры BL - immediate constant, BH - destantion
     bswap   EBX

     movzx   EAX, BH

     mov     byte ptr[RFILE+EAX], BL
     jmp     @AVR_EXIT
AVR_CP:
     mov     EBX, dword ptr[RFILE+EBX]
     cmp     BL,  byte ptr[RFILE+EAX]
     pushfd
     pop     dword ptr [FLAGS86]
     jmp     @AVR_EXIT
AVR_SUB:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     sub     byte ptr[RFILE+EBX], CL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_ADC:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     sahf

     adc     byte ptr[RFILE+EBX], CL
     lahf

     seto    AL
     mov     dword ptr [FLAGS86], EAX

     jmp     @AVR_EXIT
AVR_AND:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     and     byte ptr[RFILE+EBX], CL
     lahf

     mov     dword ptr [FLAGS86], EAX
     jmp     @AVR_EXIT
AVR_EOR:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     xor     byte ptr[RFILE+EBX], CL
     lahf

     mov     dword ptr [FLAGS86], EAX
     jmp     @AVR_EXIT
AVR_OR:
// входные параметры BL - destantion, BH - source
     bswap   EBX

     movzx   EAX, BH

     mov     ECX, dword ptr[RFILE+EAX]
     and     EBX, $000000FF

     or      byte ptr[RFILE+EBX], CL
     lahf

     mov     dword ptr [FLAGS86], EAX
     jmp     @AVR_EXIT
AVR_RJMP:
// вход EBX старшие 16 бит - смещение, EDX - счетчик команд
     shr     EBX, 16
     add     EDX, EBX

     mov     JmpCycle, offset AVR_CPSE_Cycle_1
     and     EDX, $00000FFF

     jmp     @AVR_EXIT
//----- Cycle 1 CPSE
    AVR_CPSE_Cycle_1:
     mov     JmpCycle, offset AVR_FETCH
AVR_UNKNOWN:
     jmp     @AVR_EXIT
@AVR_EXIT:
     mov     dword ptr [PC], EDX    // сохраним PC
end;
CORE_AVR_EXECUTE := (JmpCycle <> @AVR_FETCH);
end;
end;

{==============================================================================

CROSS_CODE - массив адресов (4 * ROM_SIZE байт) переходов для реализации
             инструкций AVR, каждый элемент ассоциируется с инструкцией
             в памяти программ AVR.

 Процедура транслирует код инструкций AVR в адресс эквивалентной функции
 для процессора x86 (несколько инструкций).

===============================================================================}
procedure Translate;
var
  i, ins, DES   :    integer;
  line           :    string;
begin
 for i:=0 to CODE_ROM_SIZE do begin
   ins := CODE[i];
   DES := LookUpTable[ins];
   if DES >= LAST_DES then
    Form1.Memo1.Lines.Add('Инструкция не известна, будет пропущена!')
   else begin
    with DES_AVR[DES] do begin
      CROSS_CODE[i] := translateop(ins) OR addr;
      line := format('%4.4X  %4.4X {%8.8X}    %s  ', [i, ins, CROSS_CODE[i], mnemo]) + getop(ins);
      Form1.lbxMnemo.Items.Add(line);
    end;
   end;
 end;
end;

procedure TForm1.RegFileRefresh;
var
 i,j,r : integer;
 StrFLAGS : array [0..8] of char;
 const
 // Флаги при загрузке их командой LAHF
  F86_CF : integer = $00000100;
  F86_AF : integer = $00001000;
  F86_ZF : integer = $00004000;
  F86_SF : integer = $00008000;
  F86_OF : integer = $000000FF;
begin
  for j:=0 to 1 do
   for i:=0 to 15 do begin
    r := i + j*16;
    regsgrid.Cells[j,i] := format('R%2d: %2.2x', [r,RFILE[r]]);
   end;

  StrFLAGS := '00000000';
  if (FLAGS86 AND F86_CF) <> 0 then StrFLAGS[7] := '1';
  if (FLAGS86 AND F86_ZF) <> 0 then StrFLAGS[6] := '1';
  if (FLAGS86 AND F86_SF) <> 0 then StrFLAGS[5] := '1';
  if (FLAGS86 AND F86_OF) <> 0 then StrFLAGS[4] := '1';
  if ((FLAGS86 AND F86_SF) XOR (FLAGS86 AND F86_OF)) <> 0 then StrFLAGS[3] := '1';
  if (FLAGS86 AND F86_AF) <> 0 then StrFLAGS[2] := '1';
//                                 I T H S V N Z C
  lbSREG.Caption := format('SREG: %s', [StrFLAGS]);
  lbPC.Caption := format('PC: %4.4x', [PC]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i         : integer;
  executed  : boolean;
begin
  for i:=0 to REG_FILE_SIZE do dRFILE[i] := RFILE[i];

  repeat
  // Раздача тактовой по устройствам
   core_2313.HAL;

  until not CORE_AVR_EXECUTE(false); // до тех пор пока не завершиться команда AVR

  for i:=0 to REG_FILE_SIZE do dRFILE[i] := dRFILE[i] XOR RFILE[i];
  RegFileRefresh;
  lbxMnemo.Selected[pc] := true;
  Form2.Refresh;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Form2.Show;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 i, t    : integer;
 r, d    : word;
begin
  Init;
  PC := 0;
  FLAGS86 := 0;
  JmpTableInit := false;

  for i:=0 to $3FF do begin
    t := i AND $0000020F;
    r := (t SHR 5) OR (t AND $0000000F);
    t := i AND $000001F0;
    d := t SHR 4;
    dcregs[i] := (r SHL 8) OR d;
  end;

  RegFileRefresh;
  lbxMnemo.Selected[pc] := true;
end;

procedure TForm1.logChange(Sender: TObject);
begin

end;

procedure ResetMCU;
begin
 PC := 0;
 Form1.RegFileRefresh;
 Form1.lbxMnemo.Selected[pc] := true;
end;

procedure TForm1.mnuFOClick(Sender: TObject);
begin
  if dlgFO.Execute then begin
   hBIN := FileOpen(dlgFO.FileName, fmOpenRead);
   FileRead(hBIN, CODE, $3FF);
   Translate;
   ResetMCU;
  end;
end;

procedure TForm1.regsgridDrawCell(Sender: TObject; aCol, aRow: Integer;
  aRect: TRect; aState: TGridDrawState);
begin
  if dRFILE[aCol*16+aRow] <> 0 then begin
    regsgrid.Canvas.Brush.Color:=clYellow;
    regsgrid.Canvas.FillRect(aRect);
  end;
end;

initialization
  {$I mcusim.lrs}

end.

